// ------------------------------------------------------------------------------------------------
// File   : DX9ShaderDatabase.cpp
// Date   : 2012-08-01
// Author : Weng xiao yi
// Rev.   : 
// Descr. : Create, load, store and manage shaders
//
// ------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------
// HEADERS
// ------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <tchar.h>
#include "DX9ShaderUtils.h"
#include "DX9ShaderDatabase.h"
#include "DX9VertexShader.h"
#include "DX9PixelShader.h"
#include "DX9VertexShaderManager.h"
#include "DX9PixelShaderManager.h"
// ------------------------------------------------------------------------------------------------
// DEFINITIONS
// ------------------------------------------------------------------------------------------------


// ------------------------------------------------------------------------------------------------
// CONSTANTS
// ------------------------------------------------------------------------------------------------
const ULONG DX9_SHADER_DB_MAGIC   = MAKEFOURCC('S','D','B','2');
const ULONG DX9_SHADER_DB_VERSION = 1;

const char DX9_SHADER_VS_DEFAULT[] = 
									"uniform float4x4 g_mWorldViewProj;\n"\
									"struct VSOutput\n"
									"{\n"
									"    float4 pos      : POSITION;\n"
									"    float4 color[2] : COLOR0;\n"
									"    float4 tc[8]    : TEXCOORD0;\n"
									"};\n"
									"VSOutput VSMain( in float4 _position : POSITION )\n"\
									"{\n"\
									"    VSOutput oOutput = (VSOutput)0;\n"\
									"    oOutput.pos      = mul( _position, g_mWorldViewProj );\n"\
									"    return oOutput;\n"\
									"}";

const char DX9_SHADER_PS_DEFAULT[] = 
									"float4 PSMain( void ) : COLOR0\n"\
									"{\n"\
									"    return float4( 0.125f, 0.25f, 0.5f, 0.05f );\n"\
									"}";


const char DX9_SHADER_VS_DEFAULT_11[] = 
									"vs_1_1					\n"\
									"def c4, 0, 0, 0, 0		\n"\
									"dcl_position v0		\n"\
									"dp4 oPos.x, v0, c0		\n"\
									"dp4 oPos.y, v0, c1		\n"\
									"dp4 oPos.z, v0, c2		\n"\
									"dp4 oPos.w, v0, c3		\n"\
									"mov oD0, c4.x			\n"\
									"mov oD1, c4.x			\n"\
									"mov oT0, c4.x			\n"\
									"mov oT1, c4.x			\n"\
									"mov oT2, c4.x			\n"\
									"mov oT3, c4.x			\n"\
									"mov oT4, c4.x			\n"\
									"mov oT5, c4.x			\n"\
									"mov oT6, c4.x			\n"\
									"mov oT7, c4.x			\n"\
									"";

const char DX9_SHADER_PS_DEFAULT_11[] = 
									"ps_1_1									\n"\
									"def c0, 0.125, 0.25, 0.5, 0.0500000007	\n"\
									"mov r0, c0								\n"\
									"";



const char DX9_VS_TARGET_3_0[] = "vs_3_0";
const char DX9_PS_TARGET_3_0[] = "ps_3_0";
const char DX9_VS_TARGET_2_0[] = "vs_2_0";
const char DX9_PS_TARGET_2_0[] = "ps_2_0";
const char DX9_VS_TARGET_1_1[] = "vs_1_1";
const char DX9_PS_TARGET_1_4[] = "ps_1_4";
const char DX9_PS_TARGET_1_3[] = "ps_1_3";
const char DX9_PS_TARGET_1_2[] = "ps_1_2";
const char DX9_PS_TARGET_1_1[] = "ps_1_1";

// Run on hardware thread 1 of core 0
const DWORD DX9_SHADER_COMPILATION_THREAD_PROCESSOR = 1;


// ---------------------------------------------------------------
// Global Function		- CRC Function -
// ---------------------------------------------------------------
ULONG DX9_CRCTab[256];
void DX9_InitCRC(void)
{
	int I, J;
	ULONG C;
	for(I=0;I<256;I++)
	{
		for (C=I,J=0;J<8;J++)
			C=(C & 1) ? (C>>1)^0xEDB88320L : (C>>1);
		DX9_CRCTab[I]=C;
	}
}


ULONG DX9_CalcCRC32(ULONG StartCRC,UBYTE *Addr,ULONG Size)
{
	unsigned int I;
	for(I=0; I<Size; I++)
		StartCRC = DX9_CRCTab[(UBYTE)StartCRC ^ Addr[I]] ^ (StartCRC >> 8);
	return(StartCRC);
}



// ------------------------------------------------------------------------------------------------
// IMPLEMENTATION - DX9ShaderInclude
// ------------------------------------------------------------------------------------------------
DX9ShaderInclude::DX9ShaderInclude(void)
{
}

DX9ShaderInclude::~DX9ShaderInclude(void)
{
}

// ------------------------------------------------------------------------------------------------
// Name   : Open
// Params : 
// RetVal : 
// Descr. : Get a preloaded HLSL file used for compilation
// ------------------------------------------------------------------------------------------------
HRESULT __stdcall DX9ShaderInclude::Open(D3DXINCLUDE_TYPE _eIncludeType, 
										 LPCSTR           _szFileName, 
										 LPCVOID          _pParentData, 
										 LPCVOID*         _ppData, 
										 UINT*            _pBytes)
{
	const CHAR* szStart = _szFileName;

	if(strstr(_szFileName, ".."))
	{
		szStart = _szFileName + 3;
	}

	if( !DX9GetShaderDatabase()->GetShaderFile(szStart, _ppData, _pBytes) )
		return E_FAIL;

	return S_OK;
}

HRESULT __stdcall DX9ShaderInclude::Close(LPCVOID)
{
	return S_OK;
}

// ------------------------------------------------------------------------------------------------
// IMPLEMENTATION - DX9ShaderDatabase
// ------------------------------------------------------------------------------------------------

DX9ShaderDatabase::DX9ShaderDatabase(void) : m_hFileHandle(INVALID_HANDLE_VALUE), 
											 m_ulFATOffset(0), m_ulFATCapacity(0),
											 m_ulNbShaderFiles(0), m_bReadOnly(FALSE)
{
	m_szShaderPath[0] = 0;

	m_hThreadEvents[THREAD_EVENT_STOP]    = NULL;
	m_hThreadEvents[THREAD_EVENT_REQUEST] = NULL;
	m_hThreadStartedEvent                 = NULL;
	m_hCompilationThread                  = NULL;
	m_dwCompilationThreadId               = 0;

	m_ulNbRequests         = 0;
	m_ulNbCompiledShaders  = 0;
	m_ulCurrentWriteOffset = 0;

	m_pDefaultVertexShader = NULL;
	m_pDefaultPixelShader  = NULL;

	m_pDevice = NULL;

	DX9_InitCRC();
}

DX9ShaderDatabase::~DX9ShaderDatabase(void)
{
}

// ------------------------------------------------------------------------------------------------
// Name   : Initialize
// Params : LPDIRECT3DDEVICE9 pDevice
// RetVal : 
// Descr. : Init, default shader setup, prepare compilation thread, load shader database
// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::Initialize(LPDIRECT3DDEVICE9 pDevice)
{
	m_pDevice = pDevice;

	_stprintf_s(m_szFileName,     L"%s\\OY_Shaders.BIN", GetShadersPath());
	_stprintf_s(m_szTempFileName, L"%s\\OY_Shaders.BI-", GetShadersPath());


//#if defined(DX9_SHADER_DB_VERBOSE)
//	OutputDebugStringA("[DX9SDB] Initialize() - ");
//	OutputDebugStringA(m_szFileName);
//	OutputDebugStringA("\n");
//#endif

	m_ulNbRequests        = 0;
	m_ulNbCompiledShaders = 0;
	m_ulCurrentWriteOffset = 0;

	m_pDefaultVertexShader = NULL;
	m_pDefaultPixelShader  = NULL;

	// Create the default vertex and pixel shaders
	if( m_pDefaultVertexShader == NULL || m_pDefaultPixelShader == NULL )
		CreateDefaultShaders();

	// Launch the compilation thread
	InitializeCompilationThread();

	// Pre-load all shaders
	LoadAllShaderFiles();

	// Open the database
	OpenDatabase();
}


void DX9ShaderDatabase::OnDeviceLost(void)
{
}

void DX9ShaderDatabase::OnDeviceReset(void)
{
	if(m_pDefaultVertexShader == NULL && m_pDefaultPixelShader == NULL)
	{
		CreateDefaultShaders();
	}
}

// End compilation thread, unload files
void DX9ShaderDatabase::Shutdown(void)
{
	delete m_pDefaultVertexShader;
	m_pDefaultVertexShader = NULL;
	delete m_pDefaultPixelShader;
	m_pDefaultVertexShader = NULL;

	DX9GetVertexShaderManager()->Shutdown();
	DX9GetPixelShaderManager()->Shutdown();

	// Kill the compilation thread
	ShutdownCompilationThread();

	// Unload the shader files
	UnloadAllShaderFiles();

	// Free the FAT
	m_ulFATCapacity        = 0;
	m_ulCurrentWriteOffset = 0;

	// Close the database file
	if(m_hFileHandle != INVALID_HANDLE_VALUE)
	{
		CloseHandle(m_hFileHandle);
		m_hFileHandle = INVALID_HANDLE_VALUE;
	}
}

// Add a new entry to the shader database file
// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::AddElement(ItemType       _eType, 
								   const ULONG64& _ulKey, 
								   const void*    _pBuffer, 
								   ULONG          _ulSize, 
								   ULONG64        _qwDependencies)
{

	if(m_bReadOnly)
		return;

	if(m_hFileHandle == INVALID_HANDLE_VALUE)
		return;

	DWORD dwWriteSize = 0;

	// Make sure we don't blow the FAT
	if(m_oHeader.ulNbFATEntries >= FAT_MAX_ENTRIES)
		return;

	FATEntry* pEntry = &m_aoFAT[m_oHeader.ulNbFATEntries];

	// Update the FAT
	pEntry->ulFileOffset   = m_ulCurrentWriteOffset;
	pEntry->ulFileSize     = _ulSize;
	pEntry->ulItemType     = _eType;
	pEntry->ulKey          = _ulKey;
	pEntry->qwDependencies = _qwDependencies;
	++m_oHeader.ulNbFATEntries;

	// Write the file
	SetFilePointer(m_hFileHandle, pEntry->ulFileOffset, 0, FILE_BEGIN);
	WriteFile(m_hFileHandle, _pBuffer, _ulSize, &dwWriteSize, NULL);

	// Update the offsets
	m_ulCurrentWriteOffset += _ulSize;

	// Update the FAT and the header
	WriteLastFATEntry();
	WriteHeader();

	// Make sure the file is written
	FlushFileBuffers(m_hFileHandle);

}

// Empty and prepare shader database for new entries, start compilation thread
// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::UnloadShaders(void)
{
	if (m_hFileHandle == INVALID_HANDLE_VALUE)
		return;

	// Stop all compilations
	ShutdownCompilationThread();

	// Re-load all the shader files
	LoadAllShaderFiles();

	// Unload all shaders from the database
	MergeDatabase(0, FALSE);

	// Re-start the thread
	InitializeCompilationThread();

	m_ulNbCompiledShaders = 0;
	m_ulNbRequests        = 0;

}


// Read shader database entries if shader database is present, else create a new shader database
// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::OpenDatabase(void)
{
	DWORD   dwFileAccess = GENERIC_READ;
	ULONG64 qwValidity   = 0;

	dwFileAccess |= GENERIC_WRITE;

	// Open the file
	m_hFileHandle = CreateFile(m_szFileName, dwFileAccess, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if(m_hFileHandle == INVALID_HANDLE_VALUE)
	{
#ifdef NDEBUG
		MessageBoxA( NULL, "Missing ShaderCache BIN files", "ERROR", MB_OK );
#endif
		dwFileAccess &= ~GENERIC_WRITE;
		m_hFileHandle = CreateFile(m_szFileName, dwFileAccess, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if(m_hFileHandle == INVALID_HANDLE_VALUE)
		{
			CreateDatabase();
			//m_bReadOnly = TRUE;
			
			// Missing ShaderCache BIN files, PreCache shaders and gen shaders
			PreCacheShaders();
			return;
		}
	}

	// Read the header
	if(!ReadData(&m_oHeader, sizeof(DBHeader)))
	{
		m_oHeader.ulMagic        = 0;
		m_oHeader.ulVersion      = 0;
		m_oHeader.ulNbFATEntries = 0;
	}

	// Make sure we can use the file before doing so
	if( (m_oHeader.ulMagic   != DX9_SHADER_DB_MAGIC) || 
		(m_oHeader.ulVersion != DX9_SHADER_DB_VERSION) )
	{
		// Current database is not valid, creating a new one
		CloseHandle(m_hFileHandle);
		m_hFileHandle = INVALID_HANDLE_VALUE;


		CreateDatabase();
		return;
	}

	// Update the write offset
	m_ulCurrentWriteOffset = GetFileSize(m_hFileHandle, NULL);

	// Read the shader entries so that we can determine the validity masks
	ReadShaderEntries(&qwValidity);

	if(qwValidity == 0xffffffffffffffff)
	{
		// All shaders are valid - Read the database as-is
		ReadDatabase();
	}
	else if (qwValidity == 0)
	{
		//OpenDatabase() - All shaders are invalid, create a new database
		// All shaders are invalid - Create a new database
		CloseHandle(m_hFileHandle);
		m_hFileHandle = INVALID_HANDLE_VALUE;

		CreateDatabase();
	}
	else
	{
		//OpenDatabase() - Some shaders are invalid, creating a new database while recovering resources from the old one
		// Some shaders are valid - Try to reuse as much as possible from the database
		MergeDatabase(qwValidity);
	}
}

void DX9ShaderDatabase::CreateDatabase(void)
{

	// Initialize the header
	m_oHeader.ulMagic         = DX9_SHADER_DB_MAGIC;
	m_oHeader.ulVersion       = DX9_SHADER_DB_VERSION;
	m_oHeader.ulNbShaders     = m_ulNbShaderFiles;
	m_oHeader.ulNbFATEntries  = 0;
	m_oHeader.ulShadersOffset = sizeof(DBHeader);
	m_oHeader.ulFATOffset     = m_oHeader.ulShadersOffset + ComputeShaderEntriesSize();

	// Data write offset
	m_ulCurrentWriteOffset = m_oHeader.ulFATOffset + FAT_MAX_ENTRIES * sizeof(FATEntry);

	// Create the file
	m_hFileHandle = CreateFile(m_szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if(m_hFileHandle == INVALID_HANDLE_VALUE)
	{
		// Try opening in read-only mode

		m_hFileHandle = CreateFile(m_szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		DWORD err = GetLastError();
		//        DX9ValidateRet(0, , "Break");
		err++;

		if(m_hFileHandle != INVALID_HANDLE_VALUE)
		{
			m_bReadOnly = TRUE;
			return;
		}
	}
	//    DX9ValidateRet(m_hFileHandle != INVALID_HANDLE_VALUE, , "Unable to create the shader database");

	// Clear the FAT
	memset(m_aoFAT, 0, FAT_MAX_ENTRIES * sizeof(FATEntry));

	// Write to the file
	WriteHeader();
	WriteShaderEntries();
	WriteFAT();

	// Make sure the file is written
	FlushFileBuffers(m_hFileHandle);
}

ULONG DX9ShaderDatabase::ComputeShaderEntriesSize(void) const
{
	ULONG ulSize = 0;
	ULONG i;

	for(i = 0; i < m_ulNbShaderFiles; ++i)
	{
		ulSize += sizeof(ShaderEntry);
		ulSize += m_apoShaderFiles[i].ulFileSize;
	}

	return ulSize;
}



void DX9ShaderDatabase::ReadDatabase(void)
{

	if(m_oHeader.ulNbFATEntries == 0)
		return;

	ULONG ulBufferSize = 16 * 1024;
	void* pBuffer = malloc(ulBufferSize);

	ULONG i;

	// Read the FAT
	if(SetFilePointer(m_hFileHandle, m_oHeader.ulFATOffset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
	{

		CloseHandle(m_hFileHandle);
		m_hFileHandle = INVALID_HANDLE_VALUE;
		CreateDatabase();


		free((BYTE*)pBuffer);
		pBuffer = NULL;
		return;
	}

	if(!ReadData(&m_aoFAT, m_oHeader.ulNbFATEntries * sizeof(FATEntry)))
	{

		CloseHandle(m_hFileHandle);
		m_hFileHandle = INVALID_HANDLE_VALUE;
		CreateDatabase();

		free((BYTE*)pBuffer);
		pBuffer = NULL;
		return;
	}

	// Create all resources
	for(i = 0; i < m_oHeader.ulNbFATEntries; ++i)
	{
		if(m_aoFAT[i].ulFileSize == 0)
			continue;

		if(m_aoFAT[i].ulFileSize > ulBufferSize)
		{
			free((BYTE*)pBuffer);
			pBuffer = NULL;

			ulBufferSize = m_aoFAT[i].ulFileSize;
			pBuffer      = malloc(ulBufferSize);
		}

		if(SetFilePointer(m_hFileHandle, m_aoFAT[i].ulFileOffset, 0, NULL) == INVALID_SET_FILE_POINTER)
		{

			CloseHandle(m_hFileHandle);
			m_hFileHandle = INVALID_HANDLE_VALUE;
			CreateDatabase();

			free((BYTE*)pBuffer);
			pBuffer = NULL;
			return;
		}

		if(!ReadData(pBuffer, m_aoFAT[i].ulFileSize))
		{

			CloseHandle(m_hFileHandle);
			m_hFileHandle = INVALID_HANDLE_VALUE;
			CreateDatabase();

			free((BYTE*)pBuffer);
			pBuffer = NULL;
			return;
		}

		switch(m_aoFAT[i].ulItemType)
		{
		case ItemVertexShader:
			DX9GetVertexShaderManager()->PreLoadShader((ULONG64)m_aoFAT[i].ulKey, pBuffer);
//#if defined(DX9_MEMORY_INFO)
//			DX9GetMemoryInfo()->AddVertexShader(m_aoFAT[i].ulFileSize);
//#endif
			break;

		case ItemPixelShader:
			DX9GetPixelShaderManager()->PreLoadShader((ULONG64)m_aoFAT[i].ulKey, pBuffer);
//#if defined(DX9_MEMORY_INFO)
//			DX9GetMemoryInfo()->AddPixelShader(m_aoFAT[i].ulFileSize);
//#endif
			break;

		default:
			//DX9Validate(FALSE, "Invalid resource type in the shader database");
			break;
		}
	}

	free((BYTE*)pBuffer);
	pBuffer = NULL;
}

// ------------------------------------------------------------------------------------------------
// Name   : MergeDatabase
// Params : 
// RetVal : 
// Descr. : The shader database is partially valid, reuse the shader entries that are still good,
//          create a new database using only the valid entries
// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::MergeDatabase(ULONG64 _qwValidity, BOOL _bPreLoadResources)
{
	//DX9ValidateRet(m_hFileHandle != INVALID_HANDLE_VALUE, , "Unable to merge the shader database");

	ULONG ulPrevFATOffset = m_oHeader.ulFATOffset;
	ULONG ulPrevFATSize   = m_oHeader.ulNbFATEntries;
	ULONG i;

	// Delete the temporary DB if any
	DeleteFile(m_szTempFileName);

	// Close the current database
	CloseHandle(m_hFileHandle);
	m_hFileHandle = INVALID_HANDLE_VALUE;

	// Rename the current database
	MoveFile(m_szFileName, m_szTempFileName);

	// Create a new database
	CreateDatabase();

	// Read the old database file and add valid elements to the new one
	{
		HANDLE    hFile        = INVALID_HANDLE_VALUE;
		FATEntry* paoFAT       = (FATEntry*)malloc(ulPrevFATSize * sizeof(FATEntry));

		DWORD     dwReadSize   = 0;
		ULONG     ulBufferSize = 16 * 1024;
		void*     pBuffer      = malloc(ulBufferSize);

		// Open the file
		hFile = CreateFile(m_szTempFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

		// Read the FAT
		SetFilePointer(hFile, ulPrevFATOffset, 0, FILE_BEGIN);
		ReadFile(hFile, paoFAT, ulPrevFATSize * sizeof(FATEntry), &dwReadSize, NULL);
		// DX9Validate(dwReadSize == (ulPrevFATSize * sizeof(FATEntry)), "Failed to read the FAT of the old shader database");

		// Read all resources and add them to the new database
		for(i = 0; i < ulPrevFATSize; ++i)
		{
			if(paoFAT[i].ulFileSize == 0)
				continue;

			if(paoFAT[i].ulFileSize > ulBufferSize)
			{
				free((BYTE*)pBuffer);
				pBuffer = NULL;

				ulBufferSize = paoFAT[i].ulFileSize;
				pBuffer      = malloc(ulBufferSize);
			}

			// Read the resource
			SetFilePointer(hFile, paoFAT[i].ulFileOffset, 0, FILE_BEGIN);
			ReadFile(hFile, pBuffer, paoFAT[i].ulFileSize, &dwReadSize, NULL);
			//DX9Validate(dwReadSize == paoFAT[i].ulFileSize, "Failed to read a resource from the old shader database");

			switch (paoFAT[i].ulItemType)
			{
			case ItemVertexShader:
				{
					DX9VertexShaderManager::DX9VSFeatureDefault oVSFeature;

					oVSFeature.stKey.ulKey = paoFAT[i].ulKey;

					if((paoFAT[i].qwDependencies & _qwValidity) == paoFAT[i].qwDependencies)
					{
						if (_bPreLoadResources)
						{
							DX9GetVertexShaderManager()->PreLoadShader(paoFAT[i].ulKey, pBuffer);
						}

						// Add to the database
						AddElement(ItemVertexShader, paoFAT[i].ulKey, pBuffer, paoFAT[i].ulFileSize, paoFAT[i].qwDependencies);
					}
				}
				break;

			case ItemPixelShader:
				{
					DX9PixelShaderManager::DX9PSFeatureDefault oPSFeature;

					oPSFeature.stKey.ulKey = (ULONG64)paoFAT[i].ulKey;

					if((paoFAT[i].qwDependencies & _qwValidity) == paoFAT[i].qwDependencies)
					{
						if(_bPreLoadResources)
						{
							DX9GetPixelShaderManager()->PreLoadShader((ULONG64)paoFAT[i].ulKey, pBuffer);
						}

						// Add to the database
						AddElement(ItemPixelShader, paoFAT[i].ulKey, pBuffer, paoFAT[i].ulFileSize, paoFAT[i].qwDependencies);
					}
				}
				break;

			default:
				// DX9Validate(FALSE, "Invalid resource type in the old shader database");
				break;
			}
		}

		CloseHandle(hFile);

		free((BYTE*)pBuffer);
		free((BYTE*)paoFAT);
		pBuffer = NULL;
		paoFAT = NULL;

	}

	// Delete the temporary database
	DeleteFile(m_szTempFileName);
}

// ------------------------------------------------------------------------------------------------
// Name   : LoadAllShaderFiles
// Params : 
// RetVal : 
// Descr. : Load all HLSL sources for shader compilation
// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::LoadAllShaderFiles(void)
{

	// Make sure we are not loading the files twice
	UnloadAllShaderFiles();



	// [Warning] Always add new files at the end because LoadShaderFile
	//           is creating a bit mask for each of the included shaders.
	//           Adding new files in the middle would mess up the references.

	// common files

	HRESULT hr = D3D_OK;

	hr = LoadShaderFile(L"DX9FeatureDefinitions.h");

	hr = LoadShaderFile(L"VsCommon.hlsl");
	hr = LoadShaderFile(L"PsCommon.hlsl");


	hr = LoadShaderFile(L"AfterEffectCommon.hlsl");
	hr = LoadShaderFile(L"VSAfterEffect.hlsl");
	hr = LoadShaderFile(L"PSAfterEffect.hlsl");

	hr = LoadShaderFile(L"AdvancedWaterCommon.hlsl");
	hr = LoadShaderFile(L"VSAdvancedWater.hlsl");
	hr = LoadShaderFile(L"PSAdvancedWater.hlsl");


	hr = LoadShaderFile(L"VsSpaceBump.hlsl");
	hr = LoadShaderFile(L"PsSpaceBump.hlsl");


	hr = LoadShaderFile(L"VsSoftParticle.hlsl");
	hr = LoadShaderFile(L"PsSoftParticle.hlsl");

	hr = LoadShaderFile(L"DynamicWeatherCommon.hlsl");
	hr = LoadShaderFile(L"VsDynamicWeather.hlsl");
	hr = LoadShaderFile(L"PsDynamicWeather.hlsl");

//#ifndef NDEBUG
//	// In Debug mode, missing shader files, so DO NOT use shader
//	if( FAILED(hr) )
//	{
//		GetHR3DConfig()->m_VSShaderVer = 0;
//		GetHR3DConfig()->m_PSShaderVer = 0;
//	}
//#endif

}

void DX9ShaderDatabase::UnloadAllShaderFiles(void)
{
	ULONG i;

	for(i = 0; i < m_ulNbShaderFiles; ++i)
	{
		free((BYTE*)(m_apoShaderFiles[i].pFileBuffer));
		m_apoShaderFiles[i].pFileBuffer = NULL;
	}

	m_ulNbShaderFiles = 0;
}

HRESULT DX9ShaderDatabase::LoadShaderFile(const TCHAR* _szShaderName)
{
	void* pFileBuffer;
	TCHAR szFilePath[DB_MAX_NAME];
	ULONG ulFileSize;
	FILE* pFile = NULL;

	_stprintf_s(szFilePath, L"%s\\%s", GetShadersPath(), _szShaderName);

	errno_t err;
	if( (err = _tfopen_s(&pFile, szFilePath, L"rb")) != 0 )
	{
//#if defined(DX9_SHADER_DB_VERBOSE)
//		OutputDebugStringA("[DX9SDB] Debug: Failed to open ");
//		OutputDebugStringA(_szShaderName);
//		OutputDebugStringA("- NOT critical, the file will be loaded later from the database\n");
//#endif
		return E_FAIL;
	}

	// Get the size of the file
	fseek(pFile, 0, SEEK_END);
	ulFileSize = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);

	// Read the content of the file
	pFileBuffer = malloc(ulFileSize + 1);
	memset(pFileBuffer, 0, ulFileSize + 1);
	fread(pFileBuffer, ulFileSize, 1, pFile);

	fclose(pFile);

	AddShaderFile(_szShaderName, pFileBuffer, ulFileSize);

	return S_OK;
}

DX9ShaderDatabase::ShaderFile* DX9ShaderDatabase::AddShaderFile(const TCHAR* _szShaderName, void* _pFileBuffer, ULONG _ulFileSize)
{
	//DX9ValidateRet(m_ulNbShaderFiles < SHADER_MAX_FILES, NULL, "Too many shaders, increase SHADER_MAX_FILES");

	ShaderFile* pShaderFile = &m_apoShaderFiles[m_ulNbShaderFiles];

	// Store a lower case version of the name so that it will be easier to compare
	_tcscpy_s(pShaderFile->szFileName, _szShaderName);
	_tcslwr_s(pShaderFile->szFileName);

	pShaderFile->pFileBuffer = _pFileBuffer;
	pShaderFile->ulFileCRC   = (ULONG)(DX9_CalcCRC32(0xFFFFFFFFL, (UBYTE *)_pFileBuffer, _ulFileSize));
	pShaderFile->ulFileSize  = _ulFileSize;
	pShaderFile->qwFileMask  = ((ULONG64)1 << m_ulNbShaderFiles);

	++m_ulNbShaderFiles;

	return pShaderFile;
}

const TCHAR* DX9ShaderDatabase::GetShadersPath(void)
{
	if(m_szShaderPath[0] == 0)
	{
		TCHAR strDir[MAX_PATH];
		GetModuleFileName( GetModuleHandle(NULL), strDir, MAX_PATH);
		_tcsrchr(strDir,L'\\')[0] = 0;

		//int charnum = WideCharToMultiByte( CP_ACP, NULL, strDir, -1, NULL, 0, NULL, FALSE );
		//static char pValue[MAX_PATH];
		//WideCharToMultiByte(CP_ACP, NULL, strDir, -1, pValue, charnum, NULL, FALSE);
		_stprintf_s(m_szShaderPath, L"%s\\Shaders", strDir);
	}

	return m_szShaderPath;
}

BOOL DX9ShaderDatabase::ReadData(void* _pBuffer, DWORD _dwSize)
{
	if(m_hFileHandle == INVALID_HANDLE_VALUE)
		return FALSE;

	DWORD dwNbBytes = 0;

	if(!ReadFile(m_hFileHandle, _pBuffer, _dwSize, &dwNbBytes, NULL))
	{
		
		return FALSE;
	}

	//DX9ValidateRet(dwNbBytes == _dwSize, FALSE, "Failed while reading data from the shader database");

	return TRUE;
}

void DX9ShaderDatabase::ReadShaderEntries(ULONG64* _pqwValidity)
{
	ShaderFile* pShaderFile;
	ShaderEntry oEntry;
	void*       pShaderContent;
	ULONG       i;
	ULONG       ulNbMatches = 0;

	// Everything is valid by default
	*_pqwValidity = 0xffffffffffffffff;

	// Seek to the shader entries
	if(SetFilePointer(m_hFileHandle, m_oHeader.ulShadersOffset, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
	{
		*_pqwValidity = 0;
		return;
	}

	for(i = 0; i < m_oHeader.ulNbShaders; ++i)
	{
		// Shader file header
		if(!ReadData(&oEntry, sizeof(ShaderEntry)))
		{
			*_pqwValidity = 0;
			return;
		}

		// Read the content of the shader file
		pShaderContent = malloc(oEntry.ulFileSize + 1);
		memset(pShaderContent, 0, oEntry.ulFileSize + 1);
		ReadData(pShaderContent, oEntry.ulFileSize);

		// Create the file if it doesn't exist (always in final since the HLSL files are stored in the DB)
		pShaderFile = FindShader(oEntry.szFileName);
		if(pShaderFile == NULL)
		{
			pShaderFile = AddShaderFile(oEntry.szFileName, pShaderContent, oEntry.ulFileSize);
//#if defined(DX9_SHADER_DB_VERBOSE)
//			OutputDebugStringA("[DX9SDB] Debug: Shader file created from the database: ");
//			OutputDebugStringA(oEntry.szFileName);
//			OutputDebugStringA("\n");
//#endif
		}
		else
		{
			free((BYTE*)(pShaderContent));
		}
		pShaderContent = NULL;

		if(pShaderFile != NULL)
		{
			// Make sure the shaders are matching
			if(oEntry.qwFileMask != pShaderFile->qwFileMask)
			{
				// Shader files order changed, dependencies are all wrong!
				*_pqwValidity = 0;
//#if defined(DX9_SHADER_DB_VERBOSE)
//				OutputDebugStringA("[DX9SDB] Debug: Shader files order has changed, ");
//				OutputDebugStringA("forcing creation of a new database\n");
//#endif
			}
			else if(oEntry.ulFileCRC  != pShaderFile->ulFileCRC)
			{
				*_pqwValidity &= ~pShaderFile->qwFileMask;
//#if defined(DX9_SHADER_DB_VERBOSE)
//				OutputDebugStringA("[DX9SDB] Debug: Shader file mismatch: ");
//				OutputDebugStringA(pShaderFile->szFileName);
//				OutputDebugStringA("\n");
//#endif
			}

			++ulNbMatches;
		}
	}

	// Invalidate all shaders if no matches were found
	if(ulNbMatches == 0)
	{
		*_pqwValidity = 0;
	}
	else if(ulNbMatches != m_ulNbShaderFiles)
	{
		// Force database merge
		*_pqwValidity &= ~0x8000000000000000;
	}

}


// Find a specific source HLSL file that was loaded
// ------------------------------------------------------------------------------------------------
DX9ShaderDatabase::ShaderFile* DX9ShaderDatabase::FindShader(const TCHAR* _szName)
{
	ULONG i;

	for(i = 0; i < m_ulNbShaderFiles; ++i)
	{
		if(_tcsicmp(m_apoShaderFiles[i].szFileName, _szName) == 0)
		{
			return &m_apoShaderFiles[i];
		}
	}

	return NULL;
}

// Get a specific source HLSL file content that was loaded
// ------------------------------------------------------------------------------------------------
BOOL DX9ShaderDatabase::GetShaderFile(const CHAR* _szName, const void** _ppBuffer, UINT* _puiSize)
{
	TCHAR szShaderFileName[512];
	ShaderFile* pShaderFile = NULL;

	DWORD CharNum = MultiByteToWideChar(CP_ACP, 0, _szName, -1, NULL, 0);
	MultiByteToWideChar(CP_ACP, 0, _szName, -1, szShaderFileName, CharNum);

	//strcpy_s(szShaderFileName, _szName);
	_tcslwr_s(szShaderFileName);

	pShaderFile = FindShader(szShaderFileName);
	if (pShaderFile == NULL)
		return false;

	*_ppBuffer = pShaderFile->pFileBuffer;
	*_puiSize  = pShaderFile->ulFileSize;

	// Add to the current dependencies
	m_qwDependencies |= pShaderFile->qwFileMask;

	return true;
}

void DX9ShaderDatabase::WriteData(void* _pBuffer, DWORD _dwSize)
{
	if( m_hFileHandle == INVALID_HANDLE_VALUE )
		return;

	DWORD dwNbBytes = 0;

	WriteFile(m_hFileHandle, _pBuffer, _dwSize, &dwNbBytes, NULL);
	//DX9Validate(dwNbBytes == _dwSize, "Failed to write data to the shader database");
}

void DX9ShaderDatabase::WriteHeader(void)
{
	if(m_hFileHandle == INVALID_HANDLE_VALUE)
		return;

	SetFilePointer(m_hFileHandle, 0, NULL, FILE_BEGIN);
	WriteData(&m_oHeader, sizeof(DBHeader));
}

void DX9ShaderDatabase::WriteShaderEntries(void)
{
	ULONG i;

	if(m_hFileHandle == INVALID_HANDLE_VALUE)
		return;

	SetFilePointer(m_hFileHandle, m_oHeader.ulShadersOffset, NULL, FILE_BEGIN);

	for(i = 0; i < m_ulNbShaderFiles; ++i)
	{
		ShaderEntry oEntry;

		memset(oEntry.szFileName, 0, SHADER_MAX_NAME);
		_tcscpy_s(oEntry.szFileName, m_apoShaderFiles[i].szFileName);
		oEntry.ulFileCRC  = m_apoShaderFiles[i].ulFileCRC;
		oEntry.ulFileSize = m_apoShaderFiles[i].ulFileSize;
		oEntry.qwFileMask = m_apoShaderFiles[i].qwFileMask;

		// Save the entry header and file content
		WriteData(&oEntry, sizeof(ShaderEntry));
		WriteData(m_apoShaderFiles[i].pFileBuffer, m_apoShaderFiles[i].ulFileSize);
	}
}

void DX9ShaderDatabase::WriteFAT(void)
{
	if(m_hFileHandle == INVALID_HANDLE_VALUE)
		return;

	// Write the entire FAT buffer
	SetFilePointer(m_hFileHandle, m_oHeader.ulFATOffset, NULL, FILE_BEGIN);
	WriteData(m_aoFAT, FAT_MAX_ENTRIES * sizeof(FATEntry));
}

void DX9ShaderDatabase::WriteLastFATEntry(void)
{
	if(m_hFileHandle == INVALID_HANDLE_VALUE)
		return;

	ULONG ulEntry = m_oHeader.ulNbFATEntries - 1;

	// Only update the last FAT entry
	SetFilePointer(m_hFileHandle, m_oHeader.ulFATOffset + (ulEntry * sizeof(FATEntry)), NULL, FILE_BEGIN);
	WriteData(&m_aoFAT[ulEntry], sizeof(FATEntry));
}


//////////////////////////////////////////////////////////////////////////
//							Muiti-Thread Function
//////////////////////////////////////////////////////////////////////////
void DX9ShaderDatabase::InitializeCompilationThread(void)
{
	// Create the synchronization elements
	m_hThreadEvents[THREAD_EVENT_STOP]    = CreateEvent(NULL, TRUE, FALSE, NULL);
	m_hThreadEvents[THREAD_EVENT_REQUEST] = CreateSemaphore(NULL, 0, REQUEST_MAX, NULL);
	m_hThreadStartedEvent                 = CreateEvent(NULL, TRUE, FALSE, NULL);

	InitializeCriticalSection(&m_oCompilationRequestLock);
	InitializeCriticalSection(&m_oCompiledShadersLock);

	// Create the compilation thread (suspended mode since we will assign it to a different processor on Xenon)
	m_hCompilationThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Thread_Entry, this, CREATE_SUSPENDED, &m_dwCompilationThreadId);
	if(m_hCompilationThread != NULL)
	{
		// Start the thread
		ResumeThread(m_hCompilationThread);

		// Wait for the thread to be ready
		WaitForSingleObject(m_hThreadStartedEvent, INFINITE);

//#if defined(DX9_SHADER_DB_VERBOSE)
//		OutputDebugStringA("[DX9SDB] Initialize() - Shader compilation thread ready\n");
//#endif
	}

	// No need for the startup event anymore
	CloseHandle(m_hThreadStartedEvent);
	m_hThreadStartedEvent = NULL;

	// Sanity check
	if(m_hCompilationThread == NULL)
	{
		//DX9Validate(FALSE, "Unable to start the shader compilation thread. Please restart the application.");

		// Clean up
		ShutdownCompilationThread();
	}
}

void DX9ShaderDatabase::ShutdownCompilationThread(void)
{
	if(m_hCompilationThread != NULL)
	{
		// Request for the thread to stop and wait until it does
		SetEvent(m_hThreadEvents[THREAD_EVENT_STOP]);
		WaitForSingleObject(m_hCompilationThread, INFINITE);

		CloseHandle(m_hCompilationThread);
		m_hCompilationThread = NULL;

//#if defined(DX9_SHADER_DB_VERBOSE)
//		OutputDebugStringA("[XeSDB] Shutdown() - Shader compilation thread terminated\n");
//#endif
	}

	DeleteCriticalSection(&m_oCompilationRequestLock);
	DeleteCriticalSection(&m_oCompiledShadersLock);

	CloseHandle(m_hThreadEvents[THREAD_EVENT_STOP]);
	CloseHandle(m_hThreadEvents[THREAD_EVENT_REQUEST]);
}

DWORD WINAPI DX9ShaderDatabase::Thread_Entry(LPVOID _pUserData)
{
	((DX9ShaderDatabase*)_pUserData)->Thread_Run();

	return 0;
}

void DX9ShaderDatabase::Thread_Run(void)
{
	BOOL bMustExit = FALSE;

	// Notify the main thread that we are ready to run
	SetEvent(m_hThreadStartedEvent);

	while(!bMustExit)
	{
		switch (WaitForMultipleObjects(2, m_hThreadEvents, FALSE, INFINITE))
		{
		case THREAD_EVENT_STOP:
			bMustExit = TRUE;
			break;

		case THREAD_EVENT_REQUEST:
			Thread_ProcessRequest();
			break;
		}
	}
}

void DX9ShaderDatabase::Thread_ProcessRequest(void)
{

	CompilationRequest* pRequest       = &m_aoRequests[0];
	ID3DXBuffer*        pBuffer        = NULL;
	ID3DXConstantTable* pConstantTable = NULL;

	// Reset the dependencies
	m_qwDependencies = 0;

	// Process ONE request
	if(pRequest->ulShaderType == SHADER_VERTEX)
	{
		Thread_CompileVertexShader(pRequest, &pBuffer, &pConstantTable);
	}
	else
	{
		Thread_CompilePixelShader(pRequest, &pBuffer, &pConstantTable);
	}

	if((pBuffer != NULL) /*&& (pConstantTable != NULL)*/)
	{
		EnterCriticalSection(&m_oCompiledShadersLock);

		// Add the compiled shader to the list
		if (m_ulNbCompiledShaders < REQUEST_MAX)
		{
			CompiledShader* pCompiledShader = &m_aoCompiledShaders[m_ulNbCompiledShaders];
			++m_ulNbCompiledShaders;

			pCompiledShader->ulShaderType       = pRequest->ulShaderType;
			pCompiledShader->ulShaderKey        = pRequest->ulShaderKey;
			pCompiledShader->pBuffer            = pBuffer;
			pCompiledShader->pConstantTable     = pConstantTable;
			pCompiledShader->qwDependencies     = m_qwDependencies;
		}
		else
		{
			//DX9Validate(FALSE, "Too many compiled shaders - Increase FRAME_CREATE_MAX in DX9ShaderDatabase");
		}

		LeaveCriticalSection(&m_oCompiledShadersLock);
	}

	EnterCriticalSection(&m_oCompilationRequestLock);

	// Overwrite the first entry with the last one
	if(m_ulNbRequests > 1)
	{
		memcpy(&m_aoRequests[0], &m_aoRequests[m_ulNbRequests - 1], sizeof(CompilationRequest));
	}

	// One less request to process!
	--m_ulNbRequests;

	LeaveCriticalSection(&m_oCompilationRequestLock);
}

// ------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::Thread_CompileVertexShader(CompilationRequest*  _pRequest, 
												   ID3DXBuffer**        _ppBuffer, 
												   ID3DXConstantTable** _ppConstantTable)
{
	D3DXMACRO       astMacros[9];
	DX9ShaderInclude oIncludes;
	ID3DXBuffer*    pErrors;
	HRESULT         hr;
	ULONG           ulNbMacros = 0;

	*_ppBuffer        = NULL;
	*_ppConstantTable = NULL;


	astMacros[ulNbMacros].Name       = NULL;
	astMacros[ulNbMacros].Definition = NULL;

#ifdef SHADER_DEBUG
	{
		// Output the shader file to disk for reference.
		//char filename[100];
		//sprintf(filename, "%s\\%llx_vs.hlsl", GetShadersPath(), _pRequest->ulShaderKey);
		//FILE *fp = fopen(filename, "wt");
		//fputs(_pRequest->szEntryString, fp);
		//fclose(fp);
	}
#endif

	if( SHADERVERSION(_pRequest->ulShaderKey) < 20 )
	{
		hr = D3DXAssembleShader(_pRequest->szEntryString, (UINT)strlen(_pRequest->szEntryString), astMacros,
			&oIncludes,	_pRequest->ulCompilationFlags, _ppBuffer, &pErrors);
	}
	else
	{
		hr = D3DXCompileShader(_pRequest->szEntryString, (UINT)strlen(_pRequest->szEntryString), astMacros,
			&oIncludes, _pRequest->szEntryPoint, GetKeyVSTarget(SHADERVERSION(_pRequest->ulShaderKey)),
			_pRequest->ulCompilationFlags, _ppBuffer, &pErrors, _ppConstantTable);
	}


	if(FAILED(hr))
	{
		OutputDebugStringA("[DX9SDB] Error while compiling a vertex shader:\n");
		OutputDebugStringA("-----------------------------------------------\n");
		OutputDebugStringA(_pRequest->szEntryString);
		OutputDebugStringA("\n");
		OutputDebugStringA("-----------------------------------------------\n");
		if (pErrors != NULL)
		{
			OutputDebugStringA("D3DXError : ");
			OutputDebugStringA((const CHAR*)pErrors->GetBufferPointer());
			OutputDebugStringA("\n");
			OutputDebugStringA("-----------------------------------------------\n");
		}

		//DX9Validate(SUCCEEDED(hr), "Failed to compile a vertex shader");

		DX9_SAFE_RELEASE(*_ppBuffer);
		DX9_SAFE_RELEASE(*_ppConstantTable);

		*_ppBuffer        = NULL;
		*_ppConstantTable = NULL;
	}
#if defined(SHADER_DEBUG)
	else if(pErrors != NULL)
	{
		OutputDebugStringA("[DX9SDB] Warning while compiling a vertex shader:\n");
		OutputDebugStringA("-------------------------------------------------\n");
		OutputDebugStringA(_pRequest->szEntryString);
		OutputDebugStringA("\n");
		OutputDebugStringA("-------------------------------------------------\n");
		OutputDebugStringA("D3DXWarning : ");
		OutputDebugStringA((const CHAR*)pErrors->GetBufferPointer());
		OutputDebugStringA("\n");
		OutputDebugStringA("-------------------------------------------------\n");
	}
	else
	{
		// Output a disassembly of the code...
		ID3DXBuffer* poCodeDisassembly = NULL;

		char szComment[1024];
		sprintf_s(szComment, "// Vertex Shader \n// Compilation Flag=%08X ** Shader Type=%08X ** Shader Key=%08I64X **\n", _pRequest->ulCompilationFlags, _pRequest->ulShaderType, _pRequest->ulShaderKey);
		hr = D3DXDisassembleShader((CONST DWORD*)((*_ppBuffer)->GetBufferPointer()), FALSE, szComment, &poCodeDisassembly);

		if (FAILED(hr))
		{
			// Oups !
			DX9Verify(0);
		}
		else
		{
			OutputDebugStringA("** VERTEX SHADER ----------------------------------------\n");
			OutputDebugStringA("** SOURCE -----------------------------------------------\n");
			OutputDebugStringA(_pRequest->szEntryString);
			OutputDebugStringA("\n");

			OutputDebugStringA("** TARGET -----------------------------------------------\n");
			OutputDebugStringA((char*)poCodeDisassembly->GetBufferPointer());

			OutputDebugStringA("** VS - END -----------------------------------------------\n");
		}

		DX9_SAFE_RELEASE(poCodeDisassembly);
	}
#endif

	DX9_SAFE_RELEASE(pErrors);
}

// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void DX9ShaderDatabase::Thread_CompilePixelShader(CompilationRequest*  _pRequest, 
												  ID3DXBuffer**        _ppBuffer, 
												  ID3DXConstantTable** _ppConstantTable)
{
	D3DXMACRO         astMacros[2];
	DX9ShaderInclude oIncludes;
	ID3DXBuffer*      pErrors;
	HRESULT           hr;
	ULONG             ulNbMacros = 0;

	astMacros[ulNbMacros].Name       = NULL;
	astMacros[ulNbMacros].Definition = NULL;

	*_ppBuffer        = NULL;
	*_ppConstantTable = NULL;

#ifdef SHADER_DEBUG
	{
		// Output the shader file to disk for reference.
		//char filename[100];
		//sprintf(filename, "%s\\%llx_ps.hlsl", GetShadersPath(), _pRequest->ulShaderKey);
		//FILE *fp = fopen(filename, "wt");
		//fputs(_pRequest->szEntryString, fp);
		//fclose(fp);
	}
#endif

	if( SHADERVERSION(_pRequest->ulShaderKey) < 20 )
	{
		hr = D3DXAssembleShader(_pRequest->szEntryString, (UINT)strlen(_pRequest->szEntryString), astMacros,
			&oIncludes,	_pRequest->ulCompilationFlags, _ppBuffer, &pErrors);
	}
	else
	{
		hr = D3DXCompileShader(_pRequest->szEntryString, (UINT)strlen(_pRequest->szEntryString), astMacros,
			&oIncludes, _pRequest->szEntryPoint, GetKeyPSTarget(SHADERVERSION(_pRequest->ulShaderKey)),
			_pRequest->ulCompilationFlags, _ppBuffer, &pErrors, _ppConstantTable);
	}

	if(FAILED(hr))
	{
		OutputDebugStringA("[DX9SDB] Error while compiling a pixel shader:\n");
		OutputDebugStringA("----------------------------------------------\n");
		OutputDebugStringA(_pRequest->szEntryString);
		OutputDebugStringA("\n");
		OutputDebugStringA("----------------------------------------------\n");
		if (pErrors != NULL)
		{
			OutputDebugStringA("D3DXError : ");
			OutputDebugStringA((const CHAR*)pErrors->GetBufferPointer());
			OutputDebugStringA("\n");
			OutputDebugStringA("----------------------------------------------\n");
		}

		//DX9Validate(SUCCEEDED(hr), "Failed to compile a pixel shader");

		DX9_SAFE_RELEASE(*_ppBuffer);
		DX9_SAFE_RELEASE(*_ppConstantTable);

		*_ppBuffer        = NULL;
		*_ppConstantTable = NULL;
	}
#if defined(SHADER_DEBUG)
	else if(pErrors != NULL)
	{
		OutputDebugStringA("[DX9SDB] Warning while compiling a pixel shader:\n");
		OutputDebugStringA("------------------------------------------------\n");
		OutputDebugStringA(_pRequest->szEntryString);
		OutputDebugStringA("\n");
		OutputDebugStringA("------------------------------------------------\n");
		OutputDebugStringA("D3DXWarning : ");
		OutputDebugStringA((const CHAR*)pErrors->GetBufferPointer());
		OutputDebugStringA("\n");
		OutputDebugStringA("------------------------------------------------\n");
	}
	else
	{
		// Output a disassembly of the code...
		ID3DXBuffer* poCodeDisassembly = NULL;

		char szComment[1024];
		sprintf_s(szComment, "// Pixel Shader \n// Compilation Flag=%08X ** Shader Type=%08X ** Shader Key=%08I64X **\n", _pRequest->ulCompilationFlags, _pRequest->ulShaderType, _pRequest->ulShaderKey);
		hr = D3DXDisassembleShader((CONST DWORD*)((*_ppBuffer)->GetBufferPointer()), FALSE, szComment, &poCodeDisassembly);

		if(FAILED(hr))
		{
			// Oups !
			DX9Verify(0);
		}
		else
		{

			OutputDebugStringA("** PIXEL SHADER -----------------------------------------\n");
			OutputDebugStringA("** SOURCE -----------------------------------------------\n");
			OutputDebugStringA(_pRequest->szEntryString);
			OutputDebugStringA("\n");

			OutputDebugStringA("** TARGET -----------------------------------------------\n");
			OutputDebugStringA((char*)poCodeDisassembly->GetBufferPointer());

			OutputDebugStringA("** PS - END -----------------------------------------------\n");
		}

		DX9_SAFE_RELEASE(poCodeDisassembly);
	}

#endif

	DX9_SAFE_RELEASE(pErrors);
}


void DX9ShaderDatabase::RequestVertexShader(const ULONG64&  _ulKey, 
											const CHAR*     _szEntryString, 
											const CHAR*     _szEntryPoint,
											ULONG           _ulFlags,
											DX9ShaderMacro _oMacros)
{
	EnterCriticalSection(&m_oCompilationRequestLock);

	if(m_ulNbRequests < REQUEST_MAX)
	{
		CompilationRequest* pRequest = &m_aoRequests[m_ulNbRequests];

		// Set a dummy shader in the vertex shader manager
		DX9VertexShader* pDupVS = m_pDefaultVertexShader->Duplicate();
		DX9GetVertexShaderManager()->AddShader(_ulKey, pDupVS);

		++m_ulNbRequests;

		pRequest->ulShaderType       = SHADER_VERTEX;
		pRequest->ulShaderKey        = _ulKey;
		pRequest->ulCompilationFlags = _ulFlags;
		pRequest->oMacros            = _oMacros;

		strcpy_s(pRequest->szEntryString, _szEntryString);
		strcpy_s(pRequest->szEntryPoint,  _szEntryPoint);

		// Notify the thread that there is something to compile
		ReleaseSemaphore(m_hThreadEvents[THREAD_EVENT_REQUEST], 1, NULL);
	}
	else
	{
		//DX9Validate(FALSE, "Too many shader compilation requests - Increase REQUEST_MAX in DX9ShaderDatabase");
	}

	LeaveCriticalSection(&m_oCompilationRequestLock);
}

void DX9ShaderDatabase::RequestPixelShader(const ULONG64&  _ulKey,
										   const CHAR*     _szEntryString,
										   const CHAR*     _szEntryPoint,
										   ULONG           _ulFlags,
										   DX9ShaderMacro _oMacros)
{
	EnterCriticalSection(&m_oCompilationRequestLock);

	if(m_ulNbRequests < REQUEST_MAX)
	{
		CompilationRequest* pRequest = &m_aoRequests[m_ulNbRequests];

		// Set a dummy shader in the pixel shader manager
		DX9PixelShader* pDupPS = m_pDefaultPixelShader->Duplicate();
		DX9GetPixelShaderManager()->AddShader(_ulKey, pDupPS);

		++m_ulNbRequests;

		pRequest->ulShaderType       = SHADER_PIXEL;
		pRequest->ulShaderKey        = _ulKey;
		pRequest->ulCompilationFlags = _ulFlags;
		pRequest->oMacros            = _oMacros;

		strcpy_s(pRequest->szEntryString, _szEntryString);
		strcpy_s(pRequest->szEntryPoint,  _szEntryPoint);

		// Notify the thread that there is something to compile
		ReleaseSemaphore(m_hThreadEvents[THREAD_EVENT_REQUEST], 1, NULL);
	}
	else
	{
		//DX9Validate(FALSE, "Too many shader compilation requests - Increase REQUEST_MAX in DX9ShaderDatabase");
	}

	LeaveCriticalSection(&m_oCompilationRequestLock);
}

const char* DX9ShaderDatabase::GetVSCompilationTarget(void) const
{
	switch(GetOyD3D9Config()->m_VSShaderVer)
	{
	case 30:
		return DX9_VS_TARGET_3_0;
		break;
	case 20:
		return DX9_VS_TARGET_2_0;
		break;
	case 11:
		return DX9_VS_TARGET_1_1;
		break;

	default:
		DX9Verify(0);
		break;
	}
	return NULL;

}

const char* DX9ShaderDatabase::GetPSCompilationTarget(void) const
{
	switch(GetOyD3D9Config()->m_PSShaderVer)
	{
	case 30:
		return DX9_PS_TARGET_3_0;
		break;
	case 20:
		return DX9_PS_TARGET_2_0;
		break;
	case 14:
		return DX9_PS_TARGET_1_4;
		break;

	default:
		DX9Verify(0);
		break;
	}
	return NULL;
}

const char* DX9ShaderDatabase::GetKeyVSTarget( ULONG shader_key ) const
{
	switch(shader_key)
	{
	case 30:
		return DX9_VS_TARGET_3_0;
		break;
	case 20:
		return DX9_VS_TARGET_2_0;
		break;
	case 11:
	case 0:
		return DX9_VS_TARGET_1_1;
		break;

	default:
		DX9Verify(0);
		break;
	}
	return NULL;
}

const char* DX9ShaderDatabase::GetKeyPSTarget( ULONG shader_key ) const
{
	switch (shader_key)
	{
	case 30:
		return DX9_PS_TARGET_3_0;
		break;
	case 20:
		return DX9_PS_TARGET_2_0;
		break;
	case 14:
		return DX9_PS_TARGET_1_4;
		break;
	case 13:
		return DX9_PS_TARGET_1_3;
		break;
	case 12:
		return DX9_PS_TARGET_1_2;
		break;
	case 11:
	case 0:
		return DX9_PS_TARGET_1_1;
		break;

	default:
		DX9Verify(0);
		break;
	}
	return NULL;
}

void DX9ShaderDatabase::CreateDefaultShaders(void)
{
	CompilationRequest  oRequest;
	ID3DXBuffer*        pBuffer = NULL;
	ID3DXConstantTable* pConstantTable = NULL;

	// Compile the vertex shader
	oRequest.ulCompilationFlags = 0;
	oRequest.oMacros.ulRaw      = 0;
	if( GetOyD3D9Config()->m_VSShaderVer < 20 )
	{
		oRequest.ulShaderKey = 11;
		strcpy_s(oRequest.szEntryString, DX9_SHADER_VS_DEFAULT_11);
		strcpy_s(oRequest.szEntryPoint,  "");

		Thread_CompileVertexShader(&oRequest, &pBuffer, &pConstantTable);

		m_pDefaultVertexShader = new DX9VertexShader();
		m_pDefaultVertexShader->ReInit( (const DWORD*)pBuffer->GetBufferPointer(), TRUE );	
	}
	else
	{
		oRequest.ulShaderKey = 20;
		strcpy_s(oRequest.szEntryString, DX9_SHADER_VS_DEFAULT);
		strcpy_s(oRequest.szEntryPoint,  "VSMain");

		Thread_CompileVertexShader(&oRequest, &pBuffer, &pConstantTable);

		m_pDefaultVertexShader = new DX9VertexShader();
		m_pDefaultVertexShader->SetConstantTable(pConstantTable);
		m_pDefaultVertexShader->ReInit((const DWORD*)pBuffer->GetBufferPointer());	
	}

	m_pDefaultVertexShader->IsDefault( TRUE );

	DX9_SAFE_RELEASE(pConstantTable);
	DX9_SAFE_RELEASE(pBuffer);

	// Compile the pixel shader
	oRequest.ulCompilationFlags = 0;
	oRequest.oMacros.ulRaw      = 0;
	if( GetOyD3D9Config()->m_PSShaderVer < 20 )
	{
		oRequest.ulShaderKey = 11;
		strcpy_s(oRequest.szEntryString, DX9_SHADER_PS_DEFAULT_11);
		strcpy_s(oRequest.szEntryPoint,  "");

		Thread_CompilePixelShader(&oRequest, &pBuffer, &pConstantTable);

		m_pDefaultPixelShader = new DX9PixelShader();
		m_pDefaultPixelShader->ReInit( (const DWORD*)pBuffer->GetBufferPointer(), TRUE );
	}
	else
	{
		oRequest.ulShaderKey = 20;
		strcpy_s(oRequest.szEntryString, DX9_SHADER_PS_DEFAULT);
		strcpy_s(oRequest.szEntryPoint,  "PSMain");

		Thread_CompilePixelShader(&oRequest, &pBuffer, &pConstantTable);

		m_pDefaultPixelShader = new DX9PixelShader();
		m_pDefaultPixelShader->SetConstantTable(pConstantTable);
		m_pDefaultPixelShader->ReInit( (const DWORD*)pBuffer->GetBufferPointer() );
	}

	m_pDefaultPixelShader->IsDefault( TRUE );

	DX9_SAFE_RELEASE(pConstantTable);
	DX9_SAFE_RELEASE(pBuffer);
}

void DX9ShaderDatabase::CreateSomeShaders(void)
{
	EnterCriticalSection(&m_oCompiledShadersLock);

	ULONG ulNbShaders = min(m_ulNbCompiledShaders, FRAME_CREATE_MAX);
	ULONG i;

	for(i = 0; i < ulNbShaders; ++i)
	{
		// Start from the end so we won't have to move structures around
		CompiledShader* pCompiledShader = &m_aoCompiledShaders[m_ulNbCompiledShaders - i - 1];

		if(pCompiledShader->ulShaderType == SHADER_VERTEX)
		{
			// Create the vertex shader in the vertex shader manager
			DX9GetVertexShaderManager()->AddCreateShader(pCompiledShader->ulShaderKey,
				pCompiledShader->pBuffer->GetBufferPointer(),
				pCompiledShader->pConstantTable);

			// Add to the database
			AddElement(ItemVertexShader, pCompiledShader->ulShaderKey, 
				pCompiledShader->pBuffer->GetBufferPointer(), 
				pCompiledShader->pBuffer->GetBufferSize(),
				pCompiledShader->qwDependencies);

//#if defined(DX9_MEMORY_INFO)
//			DX9GetMemoryInfo()->AddVertexShader(pCompiledShader->pBuffer->GetBufferSize());
//#endif
		}
		else
		{
			// Create the pixel shader in the pixel shader manager
			DX9GetPixelShaderManager()->AddCreateShader(pCompiledShader->ulShaderKey,
				pCompiledShader->pBuffer->GetBufferPointer(),
				pCompiledShader->pConstantTable);

			// Add to the database
			AddElement(ItemPixelShader, pCompiledShader->ulShaderKey,
				pCompiledShader->pBuffer->GetBufferPointer(), 
				pCompiledShader->pBuffer->GetBufferSize(),
				pCompiledShader->qwDependencies);

//#if defined(DX9_MEMORY_INFO)
//			DX9GetMemoryInfo()->AddPixelShader(pCompiledShader->pBuffer->GetBufferSize());
//#endif
		}

		DX9_SAFE_RELEASE(pCompiledShader->pBuffer);
		DX9_SAFE_RELEASE(pCompiledShader->pConstantTable);
	}

	m_ulNbCompiledShaders -= ulNbShaders;

	LeaveCriticalSection(&m_oCompiledShadersLock);
}

void DX9ShaderDatabase::PreCacheShaders(void)
{
	DX9VertexShaderManager::DX9VSFeatureAfterEffect::PreCache();
	DX9VertexShaderManager::DX9VSFeatureAdvancedWater::PreCache();
	DX9VertexShaderManager::DX9VSFeatureSpaceBump::PreCache();
	DX9VertexShaderManager::DX9VSFeatureGPUSkin::PreCache();
	DX9VertexShaderManager::DX9VSFeatureShadowmap::PreCache();
	DX9VertexShaderManager::DX9VSFeatureSoftParticle::PreCache();
	DX9VertexShaderManager::DX9VSFeatureDynamicWeather::PreCache();

	DX9PixelShaderManager::DX9PSFeatureAfterEffect::PreCache();
	DX9PixelShaderManager::DX9PSFeatureAdvancedWater::PreCache();
	DX9PixelShaderManager::DX9PSFeatureSpaceBump::PreCache();
	DX9PixelShaderManager::DX9PSFeatureShadowmap::PreCache();
	DX9PixelShaderManager::DX9PSFeatureSoftParticle::PreCache();
	DX9PixelShaderManager::DX9PSFeatureDynamicWeather::PreCache();

}